#ifndef UI_H 
#define UI_H 


#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include "client.h"

extern Client* client;

void initUI();

namespace UI {
	class Fonts {
		public:
			Fonts();
			~Fonts();
			TTF_Font* getFont(const unsigned size);
			void requestFont(const unsigned size);
			void returnFont(const unsigned size);
		private:
			// map containing font data by font size
			std::map<unsigned, TTF_Font*> fontData_;
			// this holds the number of textboxs that are using this font data
			std::map<unsigned, unsigned> fontDataUsers_;
	};

	class TextBox {
		public:
			TextBox(const char* text, int x, int y, int w, int h, 
				unsigned size);
            ~TextBox();
			void blit(SDL_Surface* surface);
			virtual void tick();

			virtual void setText(const char* text);
			const char* getText() const;
			void addText(const char* text);

			void setX(const int x);
			void setY(const int y);
			void setWidth(const unsigned int w);
			int getWidth() const;
			void setHeight(const unsigned int h);
			int getHeight() const;
			unsigned getMinimumHeight();
			int getX() const;
			int getY() const;
			void setSize(const int size);
			int getSize() const;
			void setColour(const Uint8 r, const Uint8 g, const Uint8 b);
			void setCentred();
			void unsetCentred();
			void setBold();
			void unsetBold();
			void setItalic();
			void unsetItalic();
			void setUnderline();
			void unsetUnderline();
			void enable();
			void disable();
			bool getIsInvalidated();
			void setBorderColour(const SDL_Color* borderColour);
			void setFillColour(const SDL_Color* fillColour);
			void setIsBorder(const bool isBorder);
			int getView();
			void setView(const int view);
		protected:
			void render();
			int x_, y_, size_;
			unsigned w_, h_;
			int view_;
			unsigned maxLines_;
			char* text_;
			bool isEnabled_;
			bool isCentred_;
			int style_;
			SDL_Color colour_;
			SDL_Color borderColour_;
			SDL_Color fillColour_;
			bool isBorder_;
			bool isInvalidated_;
			bool isTextAdded_;
			std::vector<SDL_Surface*> lines_;
	};

	class InputBox : public TextBox {
		public:
			InputBox(int x, int y, int w, int h, unsigned size, 
					unsigned maxLength, class InputBoxEvent* returnEvent);
			virtual ~InputBox();
			void keyEvent(const SDL_KeyboardEvent &event);
			void handleKey(const SDL_keysym &keysym);
			void click();
			bool getIsActive();
			void setIsActive(const bool isActive);
			void tick();
			void setText(const char* text);
		private:
			unsigned maxLength_;
			bool isActive_;
			InputBoxEvent* returnEvent_;
			unsigned keyDownTime_;
			unsigned repeatTime_;
			bool isKeyRepeating_;
			bool isKeyDown_;
			SDL_keysym lastKeySym_;
	};

	class Button {
		public:
			Button(const int x, const int y, const int w, const int h,
					const char* text, const int textSize, class Event* clickEvent);
			~Button();
            void blit(SDL_Surface* surface);
			void click();
			void release();
			void tick();

            void enable();
            void disable();
			bool getIsInvalidated();

			void setText(const char* text);
			void setX(const int x);
			void setY(const int y);
			void setWidth(const unsigned int w);
			int getWidth() const;
			void setHeight(const unsigned int h);
			int getHeight() const;
			int getX() const;
			int getY() const;
			void setColour(const SDL_Color* colour);
			void setTextColour(const SDL_Color* colour);
		private:
			int x_, y_;
			unsigned w_, h_;
            bool isEnabled_;
            SDL_Color textColour_;
            SDL_Color colour_;
			Event* clickEvent_;
			TextBox* textBox_;
			SDL_Surface* surface_;
			SDL_Surface* surfaceClicked_;
			bool isClicked_;
			bool isInvalidated_;
	};

	class ScrollBar {
		
	};

	class Image {
		public:
			Image(int x, int y, int w, int h, const char* fn);
			virtual ~Image();
			virtual void blit(SDL_Surface* surface);
			virtual void tick();
			void loadBMP(const char* fn);
			bool getIsInvalidated();

		protected:
			int x_, y_;
			unsigned w_, h_;
			bool isInvalidated_;
			SDL_Surface* surface_;
	};

	class Window {
		public:
			Window(int x, int y, int w, int h, const char* title);
			~Window();
			void blit(SDL_Surface* surface);
			void render();
			void renderAll();
			void tick();

			bool keyEvent(const SDL_KeyboardEvent &event);
			bool mouseMotionEvent(const SDL_MouseMotionEvent &motionEvent);
			bool mouseButtonEvent(const SDL_MouseButtonEvent &buttonEvent);

			void addTextBox(TextBox* textBox);
			void addInputBox(InputBox* inputBox);
			void addButton(Button* button);
			void addImage(Image* image);

			void setTitle(const char* text);
			void setX(const int x);
			void setY(const int y);
			void setWidth(const unsigned int w);
			int getWidth() const;
			void setHeight(const unsigned int h);
			int getHeight() const;
			int getX() const;
			int getY() const;
			bool getIsActive();
			void setIsActive(const bool isActive);

		private:
			int x_, y_;
			unsigned w_, h_;
			SDL_Surface* surfaceActive_;			// just the window itself
			SDL_Surface* surfaceInactive_;
			SDL_Surface* surfaceAll_;				// includes objects also
			TextBox* title_;
			unsigned char alpha_;
			bool isClosable_;
			bool isResizable_;
			bool isMoveable_;
			bool isInvalidated_;
			bool isActive_;
          	std::vector<TextBox*> textBoxes_;
          	std::vector<InputBox*> inputBoxes_;
         	std::vector<Button*> buttons_;
         	std::vector<Image*> images_;
			std::vector<Window*> windows_;
	};

	class UI {
		public:
			UI();
			~UI();
			bool keyEvent(const SDL_KeyboardEvent &event);
			bool mouseMotionEvent(const SDL_MouseMotionEvent &motionEvent);
			bool mouseButtonEvent(const SDL_MouseButtonEvent &buttonEvent);
			void blit(SDL_Surface* surface);
			void tick();
			void addTextBox(TextBox* textBox);
			void addInputBox(InputBox* inputBox);
			void addButton(Button* button);
			void addWindow(Window* window);
			
		private:
          	std::vector<TextBox*> textBoxes_;
          	std::vector<InputBox*> inputBoxes_;
         	std::vector<Button*> buttons_;
         	std::vector<Window*> windows_;

			Uint8 lastButtons_;
			int windowDragged_;
			bool isWindowDragged_;
	};

	class Event {
		public:
			virtual void handle() = 0;
			virtual ~Event() = 0;
	};
	inline Event::~Event() { }
	
	class VoidEvent : public Event {
		public:
			virtual void handle() { }	// do nothing
	};

	class TestEvent : public Event {
		public:
			virtual void handle() { 
				std::cout << "event handled\n";
			}
	};

	class InputBoxEvent {
		public:
			virtual void handle(char* text, class InputBox* textBox) = 0;
	};

	class CoutInputBoxEvent : public InputBoxEvent {
		public:
			virtual void handle(char* text, class InputBox* textBox) {
				if (text != NULL)
					std::cout << text << std::endl;
			}
	};

	class ChatInputBoxEvent : public InputBoxEvent {
		public:
			virtual void handle(char* text, class InputBox* textBox) {
				if ((text != NULL)&&(strlen(text) > 0)) {
					client->sendChat(text);
					textBox->setText("");
				}
			}
	};


}

#endif // UI_H

